package obecto.validation
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	import obecto.event.ValidatorEvent;

	[DefaultProperty("validators")]
	public class ValidatorGroup extends EventDispatcher implements IValidator, IInteractiveValidator
	{
		private var _validators : Array;
		[ArrayElementType("obecto.validation.IValidator")]
		public function set validators(value : Array) : void 
		{
			if (value != null)
			{
				_validators = value;
				attachListeners();
			}
		}
		public function get validators() : Array 
		{
			return _validators;
		}
		
		private var _valid : Boolean = true;
		[Bindable(event="validChanged")]
		public function get valid():Boolean
		{
			return false;
		}
		
		//****************************************
		// IInteractiveValidator implementation:
		//****************************************
		private var _changed : Boolean = false;
		public function get changed() : Boolean
		{
			return _changed;
		}
		
		[Bindable(event="validChanged")]
		[Bindable(event="sourceChanged")]
		public function get changedAndValid() : Boolean
		{
			return _changed && _valid;
		}
		
		public function ValidatorGroup(target : IEventDispatcher = null)
		{
			super(target);
		}
		
		public function validate(quiet : Boolean = false) : void
		{
			var invalidValidator : IValidator;
			for each (var validator : IValidator in _validators)
			{
				validator.validate(quiet);
				if (!validator.valid)
				{
					invalidValidator = validator;
				}
			}
			
			var oldValid : Boolean = _valid;
			var newValid : Boolean = (invalidValidator == null);
			_valid = newValid;
			
			var event : ValidatorEvent;
			if (_valid)
			{
				event = new ValidatorEvent(ValidatorEvent.VALID);
			}
			else
			{
				event = new ValidatorEvent(ValidatorEvent.INVALID);
			}
			
			if (!quiet && newValid != oldValid)
			{
				dispatchEvent(event);
			}
			
			dispatchEvent(new Event("validChanged"));
		}
		
		public function reset() : void
		{
			for each (var validator : IValidator in _validators)
			{
				validator.reset();
			}
			_valid  = true;
			_changed = false;
		}
		
		private function attachListeners() : void 
		{
			for each (var validator : IValidator in _validators)
			{
				validator.addEventListener(ValidatorEvent.VALID, handleValid);
				validator.addEventListener(ValidatorEvent.INVALID, handleInvalid);
				validator.addEventListener(ValidatorEvent.CHANGE, handleChange);
			}
		}
		
		private function handleValid(e : ValidatorEvent) : void 
		{
			validate();
		}
		
		private function handleInvalid(e : ValidatorEvent) : void 
		{
			validate();
		}
		
		private function handleChange(e : ValidatorEvent) : void 
		{
			validate();
			
			if (!_changed)
			{
				_changed = true;
				dispatchEvent(new Event("sourceChanged"));
			}
		}
		
	}
}